/*
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// type.h needs to be included first because of building issues on Windows
// Type aliases we delcare are defined in other headers and make the build
// fail otherwise.
#include "sfntly/port/type.h"
#include <assert.h>
#include <stdio.h>
#include <unicode/ucnv.h>

#include <iostream>
#include <string>

#include "gtest/gtest.h"
#include "sfntly/data/memory_byte_array.h"
#include "sfntly/font.h"
#include "sfntly/font_factory.h"
#include "sfntly/table/core/cmap_table.h"
#include "sfntly/table/core/font_header_table.h"
#include "sfntly/tag.h"
#include "test/autogenerated/cmap_test_data.h"
#include "test/test_font_utils.h"
#include "test/test_utils.h"
#include "test/test_xml_utils.h"

namespace sfntly {

#if GTEST_HAS_PARAM_TEST

using ::testing::TestWithParam;
using ::testing::Values;

class CMapBasicTests : public :: testing::TestWithParam<const char*> {
 public:
  CMapBasicTests() {}
  virtual void SetUp();
  virtual void TearDown() {}

  Ptr<CMapTable> cmap_table_;
  TiXmlDocument document_;
};

void CMapBasicTests::SetUp() {
  // Loading the font
  Ptr<FontFactory> font_factory;
  font_factory.Attach(FontFactory::GetInstance());
  FontArray font_array;
  std::string font_name = "../../";
#if defined (WIN32)
  font_name += "../";
#endif
  font_name += std::string(GetParam());
  LoadFont(font_name.c_str(), font_factory, &font_array);
  ASSERT_FALSE(font_array.empty());
  Ptr<Font> font = font_array.at(0);
  ASSERT_NE(font, reinterpret_cast<Font*>(NULL));
  cmap_table_ = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
  if (!cmap_table_)
    fprintf(stderr, "No CMap: %s\n", font_name.c_str());
  ASSERT_NE(cmap_table_, reinterpret_cast<CMapTable*>(NULL));

  // Loading the XML file
  document_ = TiXmlDocument((font_name + ".xml").c_str());
  ASSERT_TRUE(document_.LoadFile());
}

TEST_P(CMapBasicTests, BasicTest) {
  TiXmlNodeVector* cmap_table = GetNodesWithName(&document_, "cmap_table");
  // A font can only have one CMap table
  ASSERT_EQ(cmap_table->size(), (size_t)1);
  TiXmlNodeVector* cmaps = GetNodesWithName(cmap_table->at(0), "cmap");
  const TiXmlAttribute* num_cmaps_attr = GetAttribute(cmap_table->at(0),
                                                      "num_cmaps");
  ASSERT_NE(num_cmaps_attr, reinterpret_cast<TiXmlAttribute*>(NULL));
  // But there may be more than one CMap in this table
  ASSERT_LE(cmaps->size(), (size_t)num_cmaps_attr->IntValue());
  for (TiXmlNodeVector::iterator it = cmaps->begin();
       it != cmaps->end(); ++it) {
    int32_t platform_id = GetAttribute(*it, "platform_id")->IntValue();
    int32_t encoding_id = GetAttribute(*it, "encoding_id")->IntValue();
    Ptr<CMapTable::CMap> cmap;
    cmap.Attach(cmap_table_->GetCMap(platform_id, encoding_id));
    if (!cmap) {
      fprintf(stderr, "Cannot test unsupported CMapFormat%d\n",
              GetAttribute(*it, "format")->IntValue());
      continue;
    }
    ASSERT_EQ(cmap->platform_id(), platform_id);
    ASSERT_EQ(cmap->encoding_id(), encoding_id);
    TiXmlNodeVector* maps = GetNodesWithName(*it, "map");
    for (TiXmlNodeVector::iterator jt = maps->begin();
         jt != maps->end(); ++jt) {
      int32_t character;
#if defined (WIN32)
      sscanf_s(GetAttribute(*jt, "char")->Value(), "%x", &character);
#else
      sscanf(GetAttribute(*jt, "char")->Value(), "%x", &character);
#endif
      int32_t glyph_id = GetAttribute(*jt, "gid")->IntValue();
      ASSERT_EQ(cmap->GlyphId(character), glyph_id);
    }
    delete maps;
  }
  delete cmaps;
  delete cmap_table;
}

INSTANTIATE_TEST_CASE_P(CMapBasicTests,
                        CMapBasicTests,
                        ::testing::ValuesIn(cmap_test_data::kAllTests));

#else

TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}

#endif  // GTEST_HAS_PARAM
}
